package middleware

import (
	"errors"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"

	"BookStack/internal/infrastructure/core"
	appErrors "BookStack/pkg/errors"
)

// JWTClaims JWT声明
type JWTClaims struct {
	UserID   uint   `json:"user_id"`
	Username string `json:"username"`
	Role     string `json:"role"`
	jwt.RegisteredClaims
}

// GenerateToken 生成JWT令牌
func GenerateToken(userID uint, username, role string) (string, error) {
	// 获取配置
	config := core.GetConfig()

	// 设置声明
	claims := JWTClaims{
		UserID:   userID,
		Username: username,
		Role:     role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(config.JWT.Expire)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
			Issuer:    config.App.Name,
		},
	}

	// 创建令牌
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签名令牌
	return token.SignedString([]byte(config.JWT.Secret))
}

// ParseToken 解析JWT令牌
func ParseToken(tokenString string) (*JWTClaims, error) {
	// 获取配置
	config := core.GetConfig()

	// 解析令牌
	token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(config.JWT.Secret), nil
	})

	if err != nil {
		return nil, err
	}

	// 验证令牌
	if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token")
}

// GetUserID 从上下文获取用户ID
func GetUserID(c *gin.Context) (uint, error) {
	value, exists := c.Get("user_id")
	if !exists {
		return 0, errors.New("user ID not found in context")
	}

	userID, ok := value.(uint)
	if !ok {
		return 0, errors.New("user ID has wrong type")
	}

	return userID, nil
}

// GetUsername 从上下文获取用户名
func GetUsername(c *gin.Context) (string, error) {
	value, exists := c.Get("username")
	if !exists {
		return "", errors.New("username not found in context")
	}

	username, ok := value.(string)
	if !ok {
		return "", errors.New("username has wrong type")
	}

	return username, nil
}

// GetUserRole 从上下文获取用户角色
func GetUserRole(c *gin.Context) (string, error) {
	value, exists := c.Get("role")
	if !exists {
		return "", errors.New("role not found in context")
	}

	role, ok := value.(string)
	if !ok {
		return "", errors.New("role has wrong type")
	}

	return role, nil
}

// JWTAuth JWT认证中间件
func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取请求头中的认证信息
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.Error(appErrors.New(appErrors.ErrCodeAuthentication, "未提供认证令牌"))
			c.Abort()
			return
		}

		// 提取令牌
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.Error(appErrors.New(appErrors.ErrCodeAuthentication, "无效的认证头格式"))
			c.Abort()
			return
		}

		// 解析令牌
		claims, err := ParseToken(parts[1])
		if err != nil {
			c.Error(appErrors.New(appErrors.ErrCodeAuthentication, "无效的认证令牌"))
			c.Abort()
			return
		}

		// 将用户信息存储在上下文中
		c.Set("user_id", claims.UserID)
		c.Set("username", claims.Username)
		c.Set("role", claims.Role)

		c.Next()
	}
}

// AdminAuth 管理员认证中间件
func AdminAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取用户角色
		role, err := GetUserRole(c)
		if err != nil {
			c.Error(appErrors.New(appErrors.ErrCodeAuthentication, "未提供认证令牌"))
			c.Abort()
			return
		}

		// 检查角色是否为管理员
		if role != "admin" && role != "superadmin" {
			c.Error(appErrors.New(appErrors.ErrCodeAuthorization, "需要管理员权限"))
			c.Abort()
			return
		}

		c.Next()
	}
}

// SuperAdminAuth 超级管理员认证中间件
func SuperAdminAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取用户角色
		role, err := GetUserRole(c)
		if err != nil {
			c.Error(appErrors.New(appErrors.ErrCodeAuthentication, "未提供认证令牌"))
			c.Abort()
			return
		}

		// 检查角色是否为超级管理员
		if role != "superadmin" {
			c.Error(appErrors.New(appErrors.ErrCodeAuthorization, "需要超级管理员权限"))
			c.Abort()
			return
		}

		c.Next()
	}
}
